/**
 * \file kernel/colormap.h 
 */

#ifndef DODO_COLORMAP_H
#define DODO_COLORMAP_H

#include <vector>

#include <dodo_plot/kernel/color.h>


namespace dodo_plot
{

/** 
 * Colormap holds an array of colors,
 * with 3 special colors:
 *	- error_color, the color for exceptions. You can get it with a certain error_index
 *	- beyond_min, the color for values less than min value
 *	- beyond_max, the color for values greater than max value
 * 
 * Colormap can be built with a few colors and specifying their index.
 * The rest colors will be interpolated
 */

class Colormap
{
public:
	typedef std::vector<Color>::iterator iterator;
	typedef std::vector<Color>::const_iterator const_iterator;

	int size() const { return value_.size(); }
	//TODO add non-const begin() and end();
	const_iterator begin() const {return value_.begin();}
	const_iterator end() const {return value_.end();}

	/// \param index can be less than 0 and greater than size() - 1.
	/// In this case, beyond_min, beyond_max or error_color will be returned. 
	const Color& operator[] (int index) const
	{
		if(index == error_index_)
			return error_value_;

		if(index >= size())
			return beyond_max_;
		else if(index < 0)
			return beyond_min_;
		else
			return value_[index];
	}

	const Color& error_color() const
	{
		return error_value_;
	}

	int error_index() const
	{
		return error_index_;
	}

	const Color& beyond_min() const
	{
		return beyond_min_;
	}

	const Color& beyond_max() const
	{
		return beyond_max_;
	}

	void set_error_color(const Color& color)
	{
		error_value_ = color;
	}
	
	/// Specify the index that represents error.
	void set_error_index(int index)
	{
		if(index < value_.size() && index >= 0)
			error_index_ = index;
		else
			error_index_ = -999;
	}

	void set_beyond_min(const Color& color)
	{
		beyond_min_ = color;
	}

	void set_beyond_max(const Color& color)
	{
		beyond_max_ = color;
	}

public:
	/**
	 * \param b and e specify a color range
	 */
	template<class Iter>
	Colormap(Iter b, Iter e) :
		value_(b, e), 
		error_value_(color_name::TRANSPARENT),
		error_index_(-999)
	{ 
		if(value_.empty())
		{
			beyond_min_ = color_name::TRANSPARENT;
			beyond_max_ = color_name::TRANSPARENT;
		}
		else
		{
			beyond_min_ = value_[0];
			beyond_max_ = value_[value_.size() - 1];
		}
	}

	/**
	 * \param index_b and index_e specify the indexs
	 */
	template<class Index_Iter, class Color_Iter>
	Colormap(Index_Iter index_b, Index_Iter index_e, Color_Iter color_b) :
		error_index_(-999),
		error_value_(color_name::TRANSPARENT)
	{
		if(index_b == index_e)
			return;

		for(int i = 0; i <= *index_b; ++i)
		{
			value_.push_back(*color_b);
		}
		int prev_index = *index_b;
		Color prev_color = *color_b;
		++index_b;
		++color_b;

		for( ;
			index_b != index_e;
			++index_b , ++color_b)
		{
			int now_index = *index_b;
			int index_distance = now_index - prev_index;
			Color now_color = *color_b;

			for(int i = prev_index + 1; i < now_index; ++i)
			{
				double ratio_now = double(i - prev_index) / index_distance;
				double ratio_prev = 1.0 - ratio_now;
				value_.push_back(
					Color(
						prev_color.r() * ratio_prev + now_color.r() * ratio_now,
						prev_color.g() * ratio_prev + now_color.g() * ratio_now,
						prev_color.b() * ratio_prev + now_color.b() * ratio_now,
						prev_color.a() * ratio_prev + now_color.a() * ratio_now
					)
				);
			}
			value_.push_back(now_color);
			prev_index = now_index;
			prev_color = now_color;
		}			
		if(value_.empty())
		{
			beyond_min_ = color_name::TRANSPARENT;
			beyond_max_ = color_name::TRANSPARENT;
		}
		else
		{
			beyond_min_ = value_[0];
			beyond_max_ = value_[value_.size() - 1];
		}
	}
	
private:
	std::vector<Color> value_;
	Color error_value_;
	int error_index_;
	Color beyond_min_;
	Color beyond_max_;
};

}

#endif //DODO_COLORMAP_H

